Skip to content

PolarFire SoC M-Mode LPDDR4 + minimal SBI runtime#774

Open
dgarske wants to merge 2 commits into
wolfSSL:masterfrom
dgarske:polarfire_ddr_2
Open

PolarFire SoC M-Mode LPDDR4 + minimal SBI runtime#774
dgarske wants to merge 2 commits into
wolfSSL:masterfrom
dgarske:polarfire_ddr_2

Conversation

@dgarske

@dgarske dgarske commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

wolfBoot fully replaces HSS (and OpenSBI) on the Microchip PolarFire SoC MPFS250T Video Kit: it boots on the E51 monitor core in M-mode from eNVM, performs software LPDDR4 init/training, loads a signed 19 MB Yocto FIT image from SD card into DDR, verifies it (SHA384 + ECC384), applies device-tree fixups, hands off a U54 hart to S-mode Linux, and stays resident as a minimal SBI runtime. Result: secure-boot 4-CPU SMP Yocto Linux to a login prompt in ~40 s from power-on, with no Microchip firmware in the boot chain.

Commits

1. PolarFire SoC: LPDDR4 init for MPFS250T Video Kit (M-Mode) (d986616)

  • Software LPDDR4 controller + PHY init/training on the E51, derived register-by-register from the Libero/HSS fpga_design_config.h (pulled in via the LIBERO_FPGA_CONFIG_DIR make variable; a CI stub keeps the path compiling in GitHub Actions).
  • Training gated on all-4-lane WRCALIB with retry, making cold-boot training reliable and independent of console timing (DEBUG_DDR is now diagnostic-only, off by default).
  • SD card load path: SDHCI PIO into an L2 staging buffer, then PDMA into DDR with per-block non-cached verify and bounded re-PDMA retry (direct CPU writes to DDR do not land on this platform).
  • FIT parse with PDMA kernel/dtb extraction and L2-buffered dtb fixups; S-mode hand-off of a U54 hart via a staged mailbox + CLINT IPI.
  • Removes per-boot DDR diagnostics whose cached-write L2 thrash corrupted L2-scratch code; adds an L2 headroom linker assert.

2. RISC-V: minimal SBI runtime; PolarFire SoC boots 4-CPU SMP Yocto Linux (8432eb5)

Generic src/riscv_sbi.c (reusable for other RISC-V M-mode targets, enabled by WOLFBOOT_MMODE_SMODE_BOOT):

  • SBI v0.2 BASE/TIME/IPI/RFENCE/HSM/DBCN + legacy calls.
  • Per-hart M-mode trap stacks switched via mscratch with a re-entrant trap entry (the trapped OS sp is a virtual address) and gp reload in the handler.
  • rdtime emulation for S/U-mode (no time CSR on these harts) and byte-wise misaligned load/store emulation via MPRV (misaligned traps are not delegatable).
  • HSM hart_start backed by per-hart start mailboxes; remote RFENCE fan-out with completion wait.

PolarFire SoC platform wiring (hal/mpfs250.c):

  • CLINT MTIME time-base enable (SYSREG RTC divider, 1 MHz, HSS parity) with all comparators parked (the reset value left MTIP pending, so parked WFIs never slept).
  • eNVM clock (ENVM_CR) programmed before the AHB clock raise (unprogrammed, eNVM reads ran out of spec and corrupted the L2-scratch code copy).
  • Cross-hart state (HSM mailboxes, IPI flags, the secondary-hart release gate) lives in the E51 DTIM and the M trap stacks in the nomap-reserved hss-buffer DDR region: cacheable stores to the L2 scratchpad can be silently lost on dirty-line eviction, which made cross-hart flags layout-dependently invisible.
  • The secondary-hart release path is UART-free and fast: Linux gives a started hart roughly 1 s to come online. wolfBoot releases the MMUART1-4 clocks/soft resets for the OS at hand-off (the kernel clock driver gates clocks but does not release peripheral soft resets; HSS normally did this).
  • Watchdog policy: the MSS WDTs always count and reset the chip at timeout and cannot be disabled, so wolfBoot does a final all-hart refresh at hand-off, the parked E51 monitor keeps petting all five, and the OS watchdog nodes are disabled via dtb fixup.
  • SDHCI software reset at hand-off so the OS driver finds a clean controller; dtb fixups for bootargs/root device and MACs from the device serial.

Validation

  • MPFS250T Video Kit, clean cold boots (power-controlled): 10/10 single-hart login gate, 5/5 SMP gate ("smp: Brought up 1 node, 4 CPUs", zero "failed to come online", login at ~40 s), 12-minute idle soaks with no watchdog reset.
  • Layout-shift robustness: a 304-byte text-shift probe that previously broke SMP bring-up passes 3/3 after the DTIM/critical-path fixes.
  • Build regression: all 5 PolarFire template configs plus versal_vmk180_sdcard, zynqmp_sdcard and zynq7000_sdcard build clean (shared files touched: sdhci.c, boot_riscv.c, vector_riscv.S, fdt.c, update_disk.c, image.c).

Notes for reviewers

  • src/vector_riscv.S trap macro changes are #ifdef WOLFBOOT_RISCV_MMODE gated; S-mode builds keep the original frame behavior (mscratch is an M-mode-only CSR).
  • src/fdt.c gains a weak wolfBoot_fit_memcpy hook so the platform can route FIT subimage copies through PDMA.
  • docs/Targets.md documents the new M-Mode + DDR Linux boot flow, the wolfSBI runtime, and the watchdog policy.

@dgarske dgarske self-assigned this May 7, 2026
Copilot AI review requested due to automatic review settings May 7, 2026 22:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds standalone wolfBoot M-mode support for the PolarFire SoC MPFS250T Video Kit, including LPDDR4 bring-up (replacing HSS in the early boot path) and Linux S-mode handoff plumbing.

Changes:

  • Enhance SDHCI diagnostics and reliability workarounds (CMD0→CMD8 delay, single-block read option, capability logging).
  • Extend RISC-V M-mode boot flow with a reusable M→S handoff API and MPFS-specific “release U54 hart” implementation.
  • Introduce MPFS250 DDR/PHY init infrastructure, build-time enablement via LIBERO_FPGA_CONFIG_DIR, new config template, and CI build job.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/sdhci.c Adds richer error logging, controller register dump, and reliability workarounds for Cadence SD4HC.
src/boot_riscv.c Adds trap register dump support (regs frame) and factors M→S handoff into overridable helpers.
hal/mpfs250.h Adds MPFS250 peripheral bits and extensive DDRC/PHY register definitions + DDR init declarations.
hal/mpfs250.c Implements MPFS250 DDR/PLL/PHY init, M→S boot on a U54 via IPI handoff, and UART reinit after PLL.
docs/Targets.md Documents new “M-Mode + DDR” configuration and build-time Libero config integration.
config/examples/polarfire_mpfs250_m.config Adds new example config for M-mode + LPDDR4 + SD + S-mode Linux boot.
arch.mk Enables MPFS DDR init when LIBERO_FPGA_CONFIG_DIR is provided (adds -DMPFS_DDR_INIT and include path).
.github/workflows/test-configs.yml Adds CI build job for the new MPFS250 M-mode + DDR config template.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hal/mpfs250.c
Comment thread hal/mpfs250.c Outdated
Comment thread hal/mpfs250.c Outdated
Comment thread hal/mpfs250.c Outdated
Comment thread src/boot_riscv.c
Comment thread src/sdhci.c
Comment thread .github/workflows/test-configs.yml
@dgarske dgarske marked this pull request as ready for review May 8, 2026 21:48
@dgarske dgarske requested a review from Copilot May 8, 2026 21:48
@dgarske dgarske force-pushed the polarfire_ddr_2 branch from 9410252 to b67a191 Compare May 8, 2026 21:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Comment thread hal/mpfs250.c Outdated
Comment thread hal/mpfs250.c
Comment thread hal/mpfs250.c
Comment thread docs/Targets.md Outdated
Comment thread hal/mpfs250.c Outdated
Comment thread src/sdhci.c Outdated
Standalone M-mode wolfBoot on the E51 (replacing HSS): software LPDDR4 init with WRCALIB all-4-lane training gate and retry, SD card secure boot of a signed 19MB Yocto FIT (SDHCI PIO + PDMA staging with per-block verify and retry; CPU writes to DDR do not land on this board), SHA384+ECC384 verification, FIT parse with PDMA kernel/dtb extraction, L2-buffered dtb fixups, and S-mode handoff of a U54 hart via mailbox+IPI. Removes the per-boot DDR diagnostics whose cached-write L2 thrash corrupted L2-scratch code, and adds an L2 headroom linker assert.
@dgarske dgarske changed the title PolarFire SoC: LPDDR4 init for MPFS250T Video Kit (M-Mode) PolarFire SoC M-Mode LPDDR4 + minimal SBI runtime Jun 12, 2026
@dgarske dgarske requested a review from Copilot June 12, 2026 23:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated 5 comments.

Comment thread src/sdhci.c
Comment on lines +37 to +39
#ifdef SDHCI_BLOCK_VIA_PDMA
extern int mpfs_pdma_memcpy(void *dst, const void *src, uint32_t bytes);
#endif
Comment thread src/sdhci.c
Comment on lines +1701 to +1713
for (retry = 0; retry < 8 && mism != 0; retry++) {
mpfs_pdma_memcpy(buf, tmp_buf + start_offset, read_sz);
*(volatile uint32_t *)0x20001000UL = 0xDEADC0DEU;
__asm__ volatile("fence iorw,iorw" ::: "memory");
mism = 0;
for (k = 0; k < read_sz; k++) {
if (ncv[k] != tmp_buf[start_offset + k]) {
mism = 1;
break;
}
}
}
}
Comment thread src/sdhci.c
Comment on lines +1774 to +1795
mism = 0;
for (retry = 0; retry < 8; retry++) {
__asm__ volatile("fence iorw,iorw" ::: "memory");
mism = 0;
for (w = 0; w < SDHCI_BLOCK_SIZE / 4U; w++) {
if (ncv[w] != sdhci_pdma_staging[w]) {
mism = 1;
break;
}
}
if (mism == 0) {
break;
}
pdma_retries++;
mpfs_pdma_memcpy(block_dst, sdhci_pdma_staging,
SDHCI_BLOCK_SIZE);
*(volatile uint32_t *)0x20001000UL = 0xDEADC0DEU;
}
if (mism != 0) {
pdma_hard++;
}
}
Comment thread src/riscv_sbi.c
#define SBI_HSM_STOPPED 1
#define SBI_HSM_START_PENDING 2

/* Register-frame indices (regs[N] == xN), see src/vector_riscv.S trap_entry */
Comment thread src/riscv_sbi.c
Comment on lines +477 to +483
if (sbi_hart_state[h] != SBI_HSM_STARTED) {
continue; /* parked harts consume MSIP in their wake loop */
}
sbi_ipi_ops[h] |= op;
__asm__ volatile("fence rw, rw" ::: "memory");
CLINT_MSIP(h) = 1U;
}
Adds a minimal M-mode SBI runtime (src/riscv_sbi.c) so wolfBoot can boot an S-mode OS with no external firmware: SBI BASE/TIME/IPI/RFENCE/HSM/DBCN plus the legacy calls; per-hart M-mode trap stacks switched via mscratch with a re-entrant trap entry (the OS stack pointer is virtual at trap time) and a wolfBoot gp reload in the handler; rdtime emulation for S and U mode (these harts have no time CSR) and byte-wise misaligned load/store emulation via MPRV (misaligned traps are not delegatable); MPRV-based guest memory access for console buffers; HSM hart_start with per-hart start mailboxes and remote RFENCE fence fan-out with completion wait.

PolarFire SoC platform wiring: CLINT MTIME time-base enable (SYSREG RTC divider, HSS parity) with all comparators parked (the reset value left MTIP pending, so parked harts' WFI never slept); eNVM clock (ENVM_CR) programmed before the AHB clock raise (HSS parity; unprogrammed it ran eNVM reads out of spec and corrupted L2-scratch code); mailbox-check-before-wfi fix in the U54 park loop; secondary harts set gp in the eNVM wake stub; cross-hart SBI state and start mailboxes live in the E51 DTIM and the M-mode trap stacks in the nomap-reserved hss-buffer DDR region, because cacheable stores to the L2 scratchpad can be lost on cache-line eviction; STACK_SIZE_PER_HART unified between the linker script and CFLAGS (the mismatch placed woken harts' stacks inside the E51 stack); watchdog policy (the MSS WDTs always count and reset at timeout: one final all-hart refresh at handoff, the parked E51 monitor keeps petting, OS watchdog nodes disabled in the dtb); SDHCI software-reset-all at handoff so the OS driver finds a clean controller; dtb fixups (no memory-node override -- the 1GB 32-bit window must not be widened over the non-cached alias; root on mmcblk0p3); DEBUG_DDR off by default (training no longer depends on printf timing thanks to the auto-init-disable reorder and the WRCALIB all-4-lane gate); obsolete bring-up diagnostics removed and the boot log reduced to milestones and errors.

Verified on the MPFS250T Video Kit: 'smp: Brought up 1 node, 4 CPUs', repeated clean cold boots to the systemd login prompt in ~40 s (10/10 and 5/5 gates), and 12-minute idle soaks with no reset.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants